package nl.haemers.data.serializers 
{
	import flash.errors.IllegalOperationError;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import nl.haemers.data.constants.DataTypes;
	import nl.haemers.data.reflection.IAccessor;
	import nl.haemers.data.reflection.IMetadata;
	import nl.haemers.data.reflection.IVariables;
	import nl.haemers.data.reflection.Type;
	import nl.haemers.data.reflection.Property;
	
	//import nl.haemers.utils.Logger;
	
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	/**
	 * ...
	 * @author Jonathan Haemers
	 */
	public class ObjectSerializer
	{
		private static var _currentLevel:Number = NaN;
		
		/** Public methods **/
		public static function getType(value:Object) : Type
		{
			_currentLevel = isNaN(_currentLevel) ? 0 : _currentLevel + 1;
			
			var classRef:Class = getDefinitionByName(getQualifiedClassName(value)) as Class;
			if (classRef == null)
			{
				//Logger.w("Error");
				return null;
			}
			
			var type:Type = new Type(_currentLevel);
			type.init(classRef);
			
			_currentLevel = _currentLevel > 0 ? _currentLevel-- : NaN;
			
			return type;
		}
		//Probably for debug only?
		public static function getProperties(value:*) : Dictionary
		{
			var type:Type = getType(value);
			if (type == null)
				throw new  IllegalOperationError("Given value is null or a Class");
			return type.getProperties();
			
			/*
			var description:XML = describeType(value);
			//Logger.i(description.toString());
			
			var properties:Dictionary = new Dictionary(true);
			//Let's get the properties 
			
			properties = searchProperties(description, "variable", properties);
			properties = searchProperties(description, "accessor", properties);
			
			return properties;
			*/
		}
		
		/** Protected methods **/
		protected static function searchProperties(description:XML, element:String, properties:Dictionary) : Dictionary
		{
			var property:Property;
			
			for each(var node:XML in description.elements(element))
			{
				if (isDataType(node.@type))
				{
					property = parseProperty(node);
				}
				else if(isCollectionType(node.@type))
				{
					property = parseComplexProperty(node);
				}
				else
				{
					trace("Empty node: " + node);
				}
				
				if (property)
				{
					properties[property.key] = property;
				}
			}
			
			return properties;
		}
		
		protected static function parseComplexProperty(node:XML) : Property
		{
			var property:Property = new Property(); //This need to be a Property collection...
			property.name = node.@name;
			property.type = node.@type;
			//Logger.i("Parse complex prop: " + node.@type);
			
			if (property.type.indexOf("__AS3__.vec::Vector.") === 0)
			{
				var vectorRegExp:RegExp = /[.*]<(.*)>[.*]?/i;
				var result:Object = vectorRegExp.exec(property.type);
				
				if (result)
				{
					//Logger.i("result: " + result);
					//Logger.i("Found result: " + result[1]);
					var vectorType:String = result[1];
					var typedObject:Object = getDefinitionByName(result[1]);
					//Logger.i(typedObject);
					
					property.child = getProperties(typedObject);
					//search the props for this new object. It could have more objects
					//We need a tree struct for this property thing parsing type.
					//After created the properties tree struct we need an easy way to loop throught the props
					//searchProperties();
				}
			}
			
			property.key = node.@name;
			for each(var metaNode:XML in node.elements("metadata"))
			{
				if (metaNode.@name == "Serialize")
				{
					if (metaNode.arg.@key == "name")
					{
						property.key = metaNode.arg.@value;
						break;
					}
				}
			}
			
			return property;
		}
		
		protected static function parseProperty(node:XML) : Property
		{
			var property:Property = new Property();
			property.name = node.@name;
			property.type = node.@type;
			property.key = node.@name;
			for each(var metaNode:XML in node.elements("metadata"))
			{
				if (metaNode.@name == "Serialize")
				{
					if (metaNode.arg.@key == "name")
					{
						property.key = metaNode.arg.@value;
						break;
					}
				}
			}
			
			return property;
		}
		
		protected static function isDataType(value:String) : Boolean
		{			
			return (value == DataTypes.BOOLEAN || value == DataTypes.INT || value == DataTypes.NUMBER || 
					value == DataTypes.STRING || value == DataTypes.UINT);
		}
		
		protected static function isCollectionType(value:String) : Boolean
		{
			//TODO: Check the Vector Datatype
			return (value == DataTypes.ARRAY || value.indexOf("__AS3__.vec::Vector.") === 0);//value == DataTypes.VECTOR
		}
		
		/** Vectory Class**/
		/*
		<type name="nl.haemers.test.data.vo::PageVO" base="Class" isDynamic="true" isFinal="true" isStatic="true">
		  <extendsClass type="Class"/>
		  <extendsClass type="Object"/>
		  <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
		  <factory type="nl.haemers.test.data.vo::PageVO">
			<extendsClass type="Object"/>
			<accessor name="url" access="readwrite" type="String" declaredBy="nl.haemers.test.data.vo::PageVO">
			  <metadata name="Serialize">
				<arg key="name" value="page"/>
			  </metadata>
			  <metadata name="__go_to_definition_help">
				<arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\PageVO.as"/>
				<arg key="pos" value="546"/>
			  </metadata>
			  <metadata name="__go_to_definition_help">
				<arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\PageVO.as"/>
				<arg key="pos" value="611"/>
			  </metadata>
			</accessor>
			<accessor name="name" access="readwrite" type="String" declaredBy="nl.haemers.test.data.vo::PageVO">
			  <metadata name="__go_to_definition_help">
				<arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\PageVO.as"/>
				<arg key="pos" value="368"/>
			  </metadata>
			  <metadata name="__go_to_definition_help">
				<arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\PageVO.as"/>
				<arg key="pos" value="435"/>
			  </metadata>
			</accessor>
			<metadata name="Serialize">
			  <arg key="name" value="page"/>
			</metadata>
			<metadata name="__go_to_ctor_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\PageVO.as"/>
			  <arg key="pos" value="229"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\PageVO.as"/>
			  <arg key="pos" value="129"/>
			</metadata>
		  </factory>
		</type>
		*/
		/*
		<type name="nl.haemers.test.data.vo::TestVO" base="Object" isDynamic="false" isFinal="false" isStatic="false">
		  <extendsClass type="Object"/>
		   <variable name="street" type="String">
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="357"/>
			</metadata>
		  </variable>
		  <variable name="hometown" type="String">
			<metadata name="Serialize">
			  <arg key="name" value="city"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="422"/>
			</metadata>
		  </variable>
		  */
		  /*
		  <accessor name="addressVO" access="readwrite" type="nl.haemers.test.data.vo::AddressVO" declaredBy="nl.haemers.test.data.vo::TestVO">
			 <metadata name="Serialize">
			  <arg key="name" value="address"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="1522"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="1601"/>
			</metadata>
		  </accessor>
		  */
		  /*
		  <accessor name="id" access="readwrite" type="int" declaredBy="nl.haemers.test.data.vo::TestVO">
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="518"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="579"/>
			</metadata>
		  </accessor>
		  <accessor name="title" access="readwrite" type="String" declaredBy="nl.haemers.test.data.vo::TestVO">
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="411"/>
			</metadata>
			<metadata name="Serialize">
				<arg key="type" value="title"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="331"/>
			</metadata>
		  </accessor>
		  <accessor name="xPos" access="readwrite" type="Number" declaredBy="nl.haemers.test.data.vo::TestVO">
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="657"/>
			</metadata>
			<metadata name="__go_to_definition_help">
			  <arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			  <arg key="pos" value="725"/>
			</metadata>
		  </accessor>
		  <metadata name="__go_to_ctor_definition_help">
			<arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			<arg key="pos" value="227"/>
		  </metadata>
		  <metadata name="__go_to_definition_help">
			<arg key="file" value="D:\work\asjlib\trunk\src\nl\haemers\test\data\vo\TestVO.as"/>
			<arg key="pos" value="93"/>
		  </metadata>
		</type>
		*/
		/** Private methods **/
		
	}

}